package org.softee.functional.functions;

import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

public class Mappers {
    private Mappers() {
    }

    /**
     * @return a function that returns the length of the input string (or null the string is null)
     */
    public static Mapper<String, Integer> stringLength() {
        return new Mapper<String, Integer>() {
            @Override
            public Integer apply(String input) {
                return (input != null) ? input.length() : null;
            }
        };
    }

    public static Mapper<Object, String> stringValue() {
        return new Mapper<Object, String>() {
            @Override
            public String apply(Object input) {
                return input.toString();
            }
        };
    }

    public static Mapper<String, Iterable<String>> split(final String regex) {
        return new Mapper<String, Iterable<String>>() {
            @Override
            public Iterable<String> apply(String input) {
                if (input == null) {
                    return Collections.emptyList();
                }
                return Arrays.asList(input.split(regex));
            }
        };
    }

    public static <F, T> Mapper<F, T> forMap(final Map<F, T> map, final T defaultValue) {
        return new Mapper<F, T>() {
            @Override
            public T apply(F input) {
                if (map.containsKey(input)) {
                    return map.get(input);
                } else {
                    return defaultValue;
                }
            }
        };
    }

    public static <F, X, T> Mapper<F, T> compound(final Mapper<F, X> f1, final Mapper<X, T> f2) {
        return new Mapper<F, T>() {
            @Override
            public T apply(F input) {
                return f2.apply(f1.apply(input));
            }
        };
    }

    public static <T> Mapper<T, T> identity() {
        return new Mapper<T, T>() {
            @Override
            public T apply(T input) {
                return input;
            }
        };
    }

    public static <T> Mapper<T, T> identityDefault(final T defaultValue) {
        return new Mapper<T, T>() {
            @Override
            public T apply(T input) {
                return (input != null) ? input : defaultValue;
            }
        };
    }

}
